﻿using System;
using FunctionalCLR.Core;
using NUnit.Framework;

namespace Zove.Test {
    [TestFixture]
    public class ExpressCLRTests : AbstractTests {

        [Test]
        public void TestHello() {
            this.TestExpression("1+2", 3);
            this.TestExpression("1-2", -1);
            this.TestExpression("1+1*2/2", 2);
            this.TestExpression("2/1", 2);
            this.TestExpression("-1", -1);
        }

        [Test]
        public void TestAbs() {
            string expr = "abs(2-1)";
            Parser p = GetParser(expr);
            Node root = p.Parse();

            string result = root.Evaluate().ToString();
            Assert.AreEqual("1", result);
        }

        [Test]
        public void TestSum() {
            string expr = "sum(1,2,3,4)";
            Parser p = GetParser(expr);
            Node root = p.Parse();

            string result = root.Evaluate().ToString();
            Assert.AreEqual("10", result);
        }

        [Test]
        public void TestEmbrace() {
            this.TestExpression("(1+2)/3", 1.0d);
            this.TestExpression("(1+2)/(2+1)", 1.0d);
        }

        [Test]
        public void TestFunction() {
            this.TestExpression("cos(1-1)", Math.Cos(0));
            this.TestExpression("sin(cos(0))", Math.Sin(1));
            this.TestExpression("sum(3,2,1)", 6);
        }

        [Test]
        public void TestNegative() {
            this.TestExpression("-1", -1);
        }

        [Test]
        public void TestBracket() {
            Parser p = GetParser("[1,2,3,4]");
            Node root = p.Parse();

            Assert.AreEqual(typeof(ListNode), root.GetType());
            Assert.AreEqual(4, ((FuncNode)root).Parameters.Count);
        }

        [Test]
        public void TestLogic() {
            TestExpression("1 < 2", true);
            TestExpression("1 > 2", false);
            TestExpression("1 <= 2", true);
            TestExpression("1 >= 2", false);

            TestExpression("(3 > 2) & (1 < 2)", true);
        }

        [Test]
        public void TestNot() {
            TestExpression("!False", true);
        }

        [Test]
        public void TestNotEqual() {
            TestExpression("3 != 4", true);
            TestExpression("3 != 3", false);
        }

        [Test]
        public void TestOr() {
            TestExpression("true | false", true);
            TestExpression("false | false", false);
        }

        [Test]
        public void TestArithmeticAndLogic() {
            TestExpression("true & (1 < 2)", true);
            TestExpression("(3 + 2*3 > 9) & (1 <= 2)", false);
            //TestExpression("((3 + 2*3*(5) >= 9) & (1 < 2)) | false", false);
            TestExpression("(3 + 2*3*(5) >= 9 & (1 > 2)) | false", false);
        }

        [Test]
        public void TestFunctionAndLogic() {
            TestExpression("abs(0-1) < 1 | (1 < 2)", true);
        }
    }
}
